﻿using System.Runtime.Serialization;
using System.IO;
using System;
using System.ServiceModel.Syndication;
using NCMIS.ObjectModel.MetaData;
using System.Xml.Serialization;
using System.Text;
using System.Xml;
using System.Collections.Generic;

namespace NCMIS.ServiceModel.Syndication
{
    /// <summary>
    /// Represents a CMIS query. Contains methods for building SELECT statements and 
    /// serialization to XML.
    /// 
    /// TO DO: Remove static parts and make them dynamic (read from config), such as the queryURI.
    /// 
    /// </summary>
    [XmlRoot(ElementName = "query")]
    public class CmisQuery
    {
        public const string queryURI = "http://cmis.alfresco.com:80/service/cmis/queries";
        XmlSerializerNamespaces xmlns = new XmlSerializerNamespaces();

        /// <summary>
        /// Build the SELECT statement using the specified search parameters.
        /// 
        /// TO DO: Fix issue with date ranges
        /// TO DO: Fix issue with IN_FOLDER (how to structure the SQL query?)
        /// </summary>
        /// <param name="sParams"></param>
        public void buildSelectStatement(Dictionary<string, Object> sParams)
        {
            string dateFormat = "yyyy-MM-ddTHH:mm:ss.fff";     // E.g. 2010-01-15T18:54:53.097+01:00

            // Search parameters
            string fileName = (string)sParams["FileName"];
            string freetext = (string)sParams["FreeText"];
            DateTime modAfter = (DateTime)sParams["ModAfter"];
            DateTime modBefore = (DateTime)sParams["ModBefore"];
            Uri currentDir = (Uri)sParams["CurrentDir"];

            // Add datetime offsets and convert to string
            string s_modAfter = modAfter.ToString(dateFormat) + DateTimeOffset.Now.ToString("%K");
            string s_modBefore = modBefore.ToString(dateFormat) + DateTimeOffset.Now.ToString("%K");

            // ID of the current folder (i.e. the folder to search within)
            string folderLocWhere = string.Format(" IN_FOLDER('{0}') AND", formatDirectoryURI(currentDir));

            // Only create additional conditions if search parameters are not empty
            string freeTextWhere = string.IsNullOrEmpty(freetext) ? "" : string.Format(" CONTAINS('{0}') AND", freetext);
            string fileNameWhere = string.IsNullOrEmpty(fileName) ? "" : string.Format(" cmis:name LIKE '%{0}%' AND", fileName);

            // Build SELECT statement
            Statement = string.Format("SELECT cmis:name, cmis:contentStreamFileName, cmis:creationDate FROM cmis:document" +
                " WHERE{0}{1}{2} cmis:creationDate > TIMESTAMP '{3}'", folderLocWhere, freeTextWhere, fileNameWhere, s_modAfter);

            // Example of typical (generated) query
            // SELECT cmis:name, cmis:contentStreamFileName, cmis:creationDate 
            // FROM cmis:document 
            // WHERE CONTAINS('william') 
            // AND IN_FOLDER('workspace://SpacesStore/87b2f129-3ad0-4a46-a6ea-05ecbfb54aa1') 
            // AND cmis:name LIKE '%Search%' 
            // AND cmis:creationDate >= TIMESTAMP '2010-01-01T00:00:00.000+01:00'
        }

        // SELECT statement node
        [XmlElement("statement")]
        public string Statement
        {
            get;
            set;
        }

        /// <summary>
        /// Serializes a query to XML and returns it as a byte array.
        /// </summary>
        /// <returns>A byte array containing the serialized data</returns>
        public byte[] ToByteArray()
        {
            // Add CMIS namespaces
            xmlns.Add("cmis", CmisNs.Cmis);
            xmlns.Add("cmisra", CmisNs.Cmisra);

            byte[] data;
            XmlSerializer xs = new XmlSerializer(this.GetType());
            using (MemoryStream memoryStream = new MemoryStream())
            {
                XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, null);
                xs.Serialize(xmlTextWriter, this, xmlns);
                data = new byte[memoryStream.Length];
                Array.Copy(memoryStream.GetBuffer(), data, data.Length);
            }
            return data;
        }

        /// <summary>
        /// Formats the given URI so that it is compatible with the IN_FOLDER() predicate.
        /// E.g. workspace://SpacesStore/87b2f129-3ad0-4a46-a6ea-05ecbfb54aa1
        /// </summary>
        /// <param name="dirURI"></param>
        /// <returns></returns>
        private string formatDirectoryURI(Uri dirURI)
        {
            string s_dirURI = dirURI.ToString();
            string match = "workspace:SpacesStore/i/";
            string prefix = "workspace://SpacesStore/";

            // Cut off everything but the folder ID 
            // E.g. "http://cmis.alfresco.com:/service/cmis/s/workspace:SpacesStore/i/87b2f129-3ad0-4a46-a6ea-05ecbfb54aa1"
            // becomes "87b2f129-3ad0-4a46-a6ea-05ecbfb54aa1"
            string tempURI = s_dirURI.Substring(s_dirURI.IndexOf(match) + match.Length);

            return (prefix + tempURI);
        }
    }
}
